package com.tcm.order.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.base.core.dozer.DozerConvert;
import com.base.core.exception.ServiceException;
import com.base.core.idworker.IdContext;
import com.base.core.lang.DateUtils;
import com.base.core.lang.LocalDateTimeUtils;
import com.base.core.lang.TimeUtils;
import com.base.core.pager.PageBean;
import com.base.core.pager.PageContext;
import com.base.core.utils.R;
import com.base.genid.generator.UidGenerator;
import com.base.threadpool.task.AsyncManager;
import com.base.threadpool.task.factory.AsyncFactory;
import com.tcm.core.service.ConfigService;
import com.tcm.order.dao.mapper.OrderItemMapper;
import com.tcm.order.dao.mapper.OrderMapper;
import com.tcm.order.domain.dto.*;
import com.tcm.order.domain.enums.BusinessCodeEnum;
import com.tcm.order.domain.enums.OrderStatusEnum;
import com.tcm.order.entity.*;
import com.tcm.order.service.*;
import com.tcm.order.service.task.async.*;
import com.tcm.prescribe.api.domain.dto.PrescribeDTO;
import com.tcm.prescribe.api.service.PrescribeService;
import com.tcm.ucenter.domain.enums.AccountTypeEnum;
import com.tcm.ucenter.service.UserAccountChangeService;
import com.tcm.ucenter.service.UserAccountFactory;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author biuco 2020年3月9日上午11:24:36
 * @Description:订单服务实现类
 */
@DubboService(version = "0.0.1-alpha", timeout = 6000, retries = 3, delay = -1)
public class OrderServiceImpl implements OrderService {


    private final OrderMapper orderMapper;

    private final OrderItemMapper orderItemMapper;


    @DubboReference(version = "0.0.1-beta", group = "cached-uid", timeout = 6000, check = false, retries = 3)
    private UidGenerator uidGenerator;


    @DubboReference(version = "0.0.1-alpha", timeout = 6000, retries = 3, check = false)
    private ConfigService configService;

    @DubboReference(version = "0.0.1-alpha", timeout = 6000, retries = 3, check = false)
    private UserAccountFactory userAccountFactory;

    @DubboReference(version = "0.0.1-alpha", timeout = 6000, retries = 3, check = false)
    private PrescribeService prescribeService;


    @Autowired
    public OrderServiceImpl(OrderMapper orderMapper, OrderItemMapper orderItemMapper) {
        this.orderMapper = orderMapper;
        this.orderItemMapper = orderItemMapper;
    }

    @Override
    @Transactional
    public Long create(OrderDTO orderDto) throws ServiceException {
        if(ObjectUtil.isEmpty(orderDto)){
            R.throwFail(BusinessCodeEnum.ORDER_PARAM_DATA_NOT_EXISTS);
        }
        if(ObjectUtil.isEmpty(orderDto.getOrderItems())){
            R.throwFail(BusinessCodeEnum.ORDER_ITEM_DATA_NOT_EXISTS);
        }
        if(ObjectUtil.isEmpty(orderDto.getQuantity()) || orderDto.getQuantity().equals(0)){
            orderDto.setQuantity(new Byte("1"));//至少要买一帖药
        }

        Order checkOrder = orderMapper.findByPlanId(orderDto.getPlanId());
        if(ObjectUtil.isNotEmpty(checkOrder)){
            R.throwFail(BusinessCodeEnum.PRESCRIBE_IS_USED);
        }

        PrescribeDTO prescribeDTO = prescribeService.findById(orderDto.getPlanId());
        if(ObjectUtil.isEmpty(prescribeDTO)){
            R.throwFail("缺少处方，请咨询医生开具处方");
        }

        Long diff = DateUtils.milliDiff(DateUtils.nowTime(),
                Objects.requireNonNull(LocalDateTimeUtils.localDateTimeToDate(
                        prescribeDTO.getCreateTime())));
        //小时数转换毫秒数
        Long toMilli = (long) (48 * 3600000);
        if(toMilli.compareTo(diff) < 0){
            R.throwFail("处方过期");
        }
        //转换对象
        Order order = DozerConvert.copyProperties(orderDto, Order.class);
        order.setBillingMoney(prescribeDTO.getBillingMoney());
        order.setServiceMoney(prescribeDTO.getServiceMoney());
        order.setDrugMoney(prescribeDTO.getDrugMoney());
        order.setQuantity(prescribeDTO.getQuantity());
        order.setTotalDrugMoney(prescribeDTO.getTotalDrugMoney());
        order.setTotalServiceMoney(prescribeDTO.getTotalServiceMoney());
        order.setTotalMoney(prescribeDTO.getTotalMoney());
        order.setBillingMoney(prescribeDTO.getBillingMoney());
        //统计计费
        BigDecimal payAmount = NumberUtil.add(order.getBillingMoney(),order.getTotalServiceMoney(),
                    order.getDecoctingFee(), order.getProcessCost(), order.getTotalDrugMoney());
        BigDecimal totalMoney = NumberUtil.add(order.getBillingMoney(),order.getTotalServiceMoney(), order.getTotalDrugMoney());
        //小计
        order.setTotalMoney(totalMoney);
        //本次修改为，判断应付金额是否>=80，如果是的话就不加运费，否则再加上运费
        if(order.getLogisticsFee().compareTo(new BigDecimal(80)) == -1){
            payAmount = NumberUtil.add(payAmount,order.getLogisticsFee());
        }
        //应付金额
        order.setPayAmount(payAmount);

        //实付金额
        order.setPayMoney(payAmount);

        //抵扣积分
        if(ObjectUtil.isNotEmpty(order.getDeductPoints()) && order.getDeductPoints() > 0){
            UserAccountChangeService userAccountChangeService = userAccountFactory.account(AccountTypeEnum.POINT.value());
            try {
                userAccountChangeService.change(order.getUserId(), - order.getDeductPoints(), "购药积分抵扣部分金额");
            } catch (ServiceException e) {
                e.printStackTrace();
                R.throwOnFail(e.getResult());
            } catch (Exception e) {
                e.printStackTrace();
                R.throwFail(e.getMessage());
            }
            //实付金额 扣除积分抵扣金额
            order.setPayMoney(NumberUtil.sub(payAmount,order.getDeductPointMoney()));
        }

        // 订单流水号(当前时间+用户ID)
        String orderSn = String.valueOf(IdContext.getInstance("code").nextId());
        order.setOrderSn(orderSn);

        order.setId(uidGenerator.getUID());
        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        orderMapper.insert(order);
        Long orderId = order.getId();

        //先转换items
        List<OrderItem> orderItems = DozerConvert.copyList(orderDto.getOrderItems(), OrderItem.class);
        for (OrderItem orderItem : orderItems) {
            orderItem.setId(uidGenerator.getUID());
            orderItem.setOrderId(orderId);
            orderItem.setOrderSn(orderSn);
            orderItem.setCreateTime(LocalDateTime.now());
            orderItem.setUpdateTime(LocalDateTime.now());
            orderItem.setSubtotal(NumberUtil.mul(orderItem.getSalePrice(), orderItem.getQuantity()));
            orderItem.setDeleted(new Byte("0"));
        }

        // 创建orderItem
        orderItemMapper.insertBatch(orderItems);
        //更新处方使用状态
        prescribeService.updateIsUse(prescribeDTO.getId());
        return order.getId();
    }

    @Override
    public int savePayment(Long orderId, String payChannel) throws Exception {
        Order order = orderMapper.findByOrderId(orderId);
        if(ObjectUtil.isNull(order)){
            R.throwFail(BusinessCodeEnum.ORDER_NOT_EXISTS);
        }
        if(order.getOrderStatus().compareTo(new Byte("1")) == 1){
            R.throwFail(BusinessCodeEnum.ORDER_IS_PAID);
        }
        order = new Order();
        order.setId(orderId);
        order.setPayChannel(payChannel);
        order.setUpdateTime(LocalDateTime.now());
        int rs = orderMapper.update(order);
        if(rs != 1){
            R.throwFail(BusinessCodeEnum.UPDATE_PAYMENT_FAIL);
        }
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cancel(Long userId, Long orderId)  throws ServiceException {
        Order order = orderMapper.findByOrderId(orderId);
        if (!order.getOrderStatus().equals(OrderStatusEnum.UNPAY.getCode())) {
            R.throwFail(BusinessCodeEnum.ORDER_CANCEL_FAIL);
        }
        Order orderUpdate = new Order();
        orderUpdate.setUpdateTime(LocalDateTime.now());
        orderUpdate.setId(orderId);
        orderUpdate.setOrderStatus(OrderStatusEnum.CANCELED.getCode());
        int count = orderMapper.update(orderUpdate);
        return count;
    }

    /**
     * 更新订单支付状态
     *
     * @return
     */
    @Override
    public void changOrderPaid(Long orderId) throws Exception {
        Order order = orderMapper.findByOrderId(orderId);
        if(ObjectUtil.isNull(order)){
            R.throwFail(BusinessCodeEnum.ORDER_NOT_EXISTS);
        }
        if (!order.getOrderStatus().equals(OrderStatusEnum.UNPAY.getCode())) {
            R.throwFail(BusinessCodeEnum.ORDER_STATUS_CHANGE_FAIL);
        }
        Order orderUpdate = new Order();
        orderUpdate.setUpdateTime(LocalDateTime.now());
        orderUpdate.setPayTime(LocalDateTime.now());
        orderUpdate.setId(order.getId());
        orderUpdate.setOrderStatus(OrderStatusEnum.PAID.getCode());
        orderMapper.update(orderUpdate);
        //发送方案
        prescribeService.sendWebService(order.getPlanId());
        //异步处理结算流水
        //医生结算财务数据
        OrderBillTaskDTO billTaskDTO = new OrderBillTaskDTO();
        BeanUtils.copyProperties(order, billTaskDTO);
        billTaskDTO.setOrderId(order.getId());
        AsyncManager.me().execute(AsyncFactory.task(billTaskDTO,OrderDoctorBillRun.class.getSimpleName()));
        //平台订单流水
        AsyncManager.me().execute(AsyncFactory.task(billTaskDTO, OrderPlatformBillRun.class.getSimpleName()));
        //药房订单流水
        AsyncManager.me().execute(AsyncFactory.task(billTaskDTO, OrderStoreBillRun.class.getSimpleName()));
        //医生邀请有礼
        AsyncManager.me().execute(AsyncFactory.task(billTaskDTO, OrderDoctorInviterBillRun.class.getSimpleName()));
        //推广人员订单流水
        AsyncManager.me().execute(AsyncFactory.task(billTaskDTO, OrderSalesmanInviterBillRun.class.getSimpleName()));

    }

    /**
     * 确认收货
     *
     * @param orderId
     */
    @Override
    public void confirmOrderStatus(Long orderId) {
        Order order = orderMapper.findByOrderId(orderId);
        if(ObjectUtil.isNull(order)){
            R.throwFail(BusinessCodeEnum.ORDER_NOT_EXISTS);
        }
        if (order.getOrderStatus().equals(OrderStatusEnum.UNPAY)) {
            R.throwFail(BusinessCodeEnum.ORDER_STATUS_CHANGE_FAIL);
        }
        Order orderUpdate = new Order();
        orderUpdate.setUpdateTime(LocalDateTime.now());
        orderUpdate.setPayTime(LocalDateTime.now());
        orderUpdate.setId(order.getId());
        orderUpdate.setOrderStatus(OrderStatusEnum.COMPLETED.getCode());
        orderMapper.update(orderUpdate);
    }

    /**
     * 订单列表
     *
     * @return
     * @throws Exception
     */
    @Override
    public PageBean<OrderDTO> listPageOrderByStatus(Byte status, Long start, Long pagesize) throws Exception {
        Long count = orderMapper.countOrderByStatus(status);
        PageContext.setCurrentPage(start);
        PageContext.setPageSize(pagesize);
        PageContext.setDataCount(count);
        if(count == 0){
            return new PageBean<>(null);
        }

        List<Order> orderList = orderMapper.listPageOrderByStatus(status,PageContext.getStart(),PageContext.getPageSize());
        List<OrderDTO> orderDTOList = orderList
                .stream().map(order -> {
                    OrderDTO orderDTO = new OrderDTO();
                    BeanUtils.copyProperties(order, orderDTO);
                    return orderDTO;
                }).collect(Collectors.toList());
        PageContext.clear();
        return new PageBean<>(orderDTOList);
    }

    /**
     * 各种状态订单统计
     * @param status
     * @return
     * @throws Exception
     */
    @Override
    public Long countOrderByStatus(Byte status) {
        Long count = orderMapper.countOrderByStatus(status);
        return count;
    }


    /**
     * 用户订单列表
     * @param userId
     * @param start
     * @param pagesize
     * @return
     * @throws ServiceException
     */
    @Override
    public PageBean<OrderDTO> listPageOrderByUser(Long userId, Long start, Long pagesize) throws ServiceException {
        Long count = orderMapper.countOrderByUser(userId, null);
        PageContext.setCurrentPage(start);
        PageContext.setPageSize(pagesize);
        PageContext.setDataCount(count);
        if(count == 0){
            return new PageBean<>(null);
        }

        List<Order> orderList = orderMapper.listPageOrderByUser(userId,null,PageContext.getStart(),PageContext.getPageSize());
        List<OrderDTO> orderDTOList = orderList
                .stream().map(order -> {
                    OrderDTO orderDTO = new OrderDTO();
                    BeanUtils.copyProperties(order, orderDTO);
                    return orderDTO;
                }).collect(Collectors.toList());
        PageContext.clear();
        return new PageBean<>(orderDTOList);
    }

    /**
     * 用户订单统计数量(订单总数)
     * @param userId
     * @return
     */
    @Override
    public Long countOrderByUser(Long userId) {
        Long count = orderMapper.countOrderByUser(userId, null);
        return count;
    }

    /**
     * 用户订单列表
     * @param userId
     * @param status
     * @param start
     * @param pagesize
     * @return
     * @throws ServiceException
     */
    @Override
    public PageBean<OrderDTO> listPageOrderByUser(Long userId, Byte status, Long start, Long pagesize) throws ServiceException {
        Long count = orderMapper.countOrderByUser(userId, status);
        PageContext.setCurrentPage(start);
        PageContext.setPageSize(pagesize);
        PageContext.setDataCount(count);
        if(count == 0){
            return new PageBean<>(null);
        }
        List<Order> orderList = orderMapper.listPageOrderByUser(userId,status,PageContext.getStart(),PageContext.getPageSize());
        List<OrderDTO> orderDTOList = orderList
                .stream().map(order -> {
                    OrderDTO orderDTO = new OrderDTO();
                    BeanUtils.copyProperties(order, orderDTO);
                    return orderDTO;
                }).collect(Collectors.toList());
        PageContext.clear();
        return new PageBean<>(orderDTOList);
    }

    /**
     * 统计各状态用户订单
     * @param userId
     * @param status
     * @return
     */
    @Override
    public Long countOrderByUser(Long userId, Byte status) {
        Long count = orderMapper.countOrderByUser(userId, status);
        return count;
    }

    /**
     * 药房订单列表
     * @param storeId
     * @param start
     * @param pagesize
     * @return
     * @throws ServiceException
     */
    @Override
    public PageBean<OrderDTO> listPageOrderByStore(Long storeId, Long start, Long pagesize) throws ServiceException {
        Long count = orderMapper.countOrderByStore(storeId, null);
        PageContext.setCurrentPage(start);
        PageContext.setPageSize(pagesize);
        PageContext.setDataCount(count);
        if(count == 0){
            return new PageBean<>(null);
        }
        List<Order> orderList = orderMapper.listPageOrderByStore(storeId,null,PageContext.getStart(),PageContext.getPageSize());
        List<OrderDTO> orderDTOList = orderList
                .stream().map(order -> {
                    OrderDTO orderDTO = new OrderDTO();
                    BeanUtils.copyProperties(order, orderDTO);
                    return orderDTO;
                }).collect(Collectors.toList());
        PageContext.clear();
        return new PageBean<>(orderDTOList);
    }

    /**
     * 药房订单列表
     * @param storeId
     * @param status
     * @param start
     * @param pagesize
     * @return
     * @throws ServiceException
     */
    @Override
    public PageBean<OrderDTO> listPageOrderByStore(Long storeId, Byte status, Long start, Long pagesize) throws ServiceException {
        Long count = orderMapper.countOrderByStore(storeId, status);
        PageContext.setCurrentPage(start);
        PageContext.setPageSize(pagesize);
        PageContext.setDataCount(count);
        if(count == 0){
            return new PageBean<>(null);
        }
        List<Order> orderList = orderMapper.listPageOrderByStore(storeId,status,PageContext.getStart(),PageContext.getPageSize());
        List<OrderDTO> orderDTOList = orderList
                .stream().map(order -> {
                    OrderDTO orderDTO = new OrderDTO();
                    BeanUtils.copyProperties(order, orderDTO);
                    return orderDTO;
                }).collect(Collectors.toList());
        PageContext.clear();
        return new PageBean<>(orderDTOList);
    }

    /**
     * 医生订单列表
     * @param doctorId
     * @param start
     * @param pagesize
     * @return
     * @throws ServiceException
     */
    @Override
    public PageBean<OrderDTO> listPageOrderByDoctor(Long doctorId, Long start, Long pagesize) throws ServiceException {
        Long count = orderMapper.countOrderByDoctor(doctorId);
        PageContext.setCurrentPage(start);
        PageContext.setPageSize(pagesize);
        PageContext.setDataCount(count);
        if(count == 0){
            return new PageBean<>(null);
        }

        List<Order> orderList = orderMapper.listPageOrderByDoctor(doctorId,PageContext.getStart(),PageContext.getPageSize());
        List<OrderDTO> orderDTOList = orderList
                .stream().map(order -> {
                    OrderDTO orderDTO = new OrderDTO();
                    BeanUtils.copyProperties(order, orderDTO);
                    return orderDTO;
                }).collect(Collectors.toList());
        PageContext.clear();
        return new PageBean<>(orderDTOList);
    }

    @Override
    public Long countOrderByDoctor(Long doctorId) {
        Long count = orderMapper.countOrderByDoctor(doctorId);
        return count;
    }


    /**
     * 获得订单详情
     *
     * @param orderId 订单id
     * @return
     * @throws Exception
     */
    @Override
    public OrderDTO findDetailByOrderId(Long orderId) throws Exception {
        Order order = orderMapper.findByOrderId(orderId);
        if(ObjectUtil.isEmpty(order)){
            return null;
        }
        OrderDTO orderDTO = new OrderDTO();
        BeanUtils.copyProperties(order, orderDTO);
        List<OrderItem> orderItems = orderItemMapper.listByOrderId(orderId);
        List<OrderItemDTO> orderItemDTOS = DozerConvert.copyList(orderItems, OrderItemDTO.class);
        orderDTO.setOrderItems(orderItemDTOS);
        return orderDTO;
    }

    /**
     * 获得订单物流信息
     *
     * @param orderId 订单id
     * @return
     */
    @Override
    public String findDeliveryInfoByOrderId(Long orderId) {
        String deliveryInfo = orderMapper.findDeliveryInfoByOrderId(orderId);
        if(ObjectUtil.isEmpty(deliveryInfo)){
            return null;
        }
        return deliveryInfo;
    }

    @Override
    public int delete(Long orderId) throws Exception {
        return orderMapper.deleteLogicByKey(orderId);
    }

    @Override
    public int emptyTrash(Long orderId) throws Exception {
        return orderMapper.deleteByKey(orderId);
    }



}
